﻿using Arim.Utils.Network;
using System;
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Arim.Evms.Web
{
    public class CameraWebSocketHandler : WebSocketHandler
    {
        ConcurrentDictionary<string, WSRtspContext> _contexts;
        public CameraWebSocketHandler(WebSocketConnectionManager webSocketConnectionManager)
            : base(webSocketConnectionManager)
        {
            _contexts = new ConcurrentDictionary<string, WSRtspContext>();
        }
        public override void OnConnected(WebSocket socket)
        {
            base.OnConnected(socket);
        }

        public override async Task OnDisconnected(WebSocket socket)
        {
            var socketId = WebSocketConnectionManager.GetId(socket);
            if (_contexts.ContainsKey(socketId))
            {
                WSRtspContext wsrtsp;
                _contexts.TryRemove(socketId, out wsrtsp);
                wsrtsp.StopReceive();
                if (wsrtsp.Rtsp != null)
                {
                    wsrtsp.Rtsp.Close();
                }
            }//关闭rtsp.
            await base.OnDisconnected(socket);
        }

        public override async Task ReceiveAsync(WebSocket socket, WebSocketReceiveResult result, byte[] buffer)
        {
            if (buffer == null || buffer.Length == 0)
                return;
            var socketId = WebSocketConnectionManager.GetId(socket);
            WSRtspContext context = null;
            if (_contexts.ContainsKey(socketId))
            {
                context = _contexts[socketId];
            }
            if (result.MessageType == WebSocketMessageType.Text)
            {
                string package = Encoding.UTF8.GetString(buffer);
                string command = getWSPCommand(package);
                string seq = getByKey(package, "seq");
                if (command == "INIT")//建立新链接.
                {
                    string host = getByKey(package, "host");
                    string port = getByKey(package, "port");
                    if (port == null)
                        port = "554";
                    if (host != null)
                    {
                        try
                        {
                            var rtsp = new RtspProxy();
                            bool connected = rtsp.Connect(host, Convert.ToInt32(port));
                            if (connected)
                            {
                                rtsp.Start();
                                context = new WSRtspContext(socket, rtsp, false)
                                {
                                    ControlWebSocketId = socketId,
                                    Seq = seq
                                };

                                _contexts.TryAdd(socketId, context);
                                //返回握手.
                                var response = new WSRtspResponse
                                {
                                    Seq = seq,
                                    Shakehand = true,
                                    Channel = socketId
                                };
                                await socket.SendAsync(response.ToArray(), WebSocketMessageType.Text, true, CancellationToken.None);
                                //启动接受rtsp控制报文，发送给ws.
                                await context.StartReceive();
                            }
                            else
                            {
                                await removeSocket(context);
                                return;
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(String.Format("connect to rtsp {0} Error:{1}", package, ex.Message));
                            return;
                        }
                    }
                }
                else if (command == "JOIN")//建立数据通道.
                {
                    string channel = getByKey(package, "channel");
                    if (channel != null && _contexts.ContainsKey(channel))
                    {
                        WSRtspContext controlContext = _contexts[channel];
                        controlContext.DataWebSocketId = socketId;

                        WSRtspContext dataContext = new WSRtspContext(socket, controlContext.Rtsp, true);
                        dataContext.ControlWebSocketId = controlContext.ControlWebSocketId;
                        dataContext.DataWebSocketId = socketId;

                        _contexts.TryAdd(socketId, dataContext);

                        //返回握手.
                        var response = new WSRtspResponse
                        {
                            Seq = seq
                        };

                        await socket.SendAsync(response.ToArray(), WebSocketMessageType.Text, true, CancellationToken.None);

                        //启动接受rtsp数据报文，发送给ws.
                        await dataContext.StartReceive();
                    }
                    return;
                }//WSP/1.1 JOIN channel: 127.0.0.1 - 2 18467 seq: 3   
                else if (context != null)
                {
                    context.Seq = seq;
                    try
                    {
                        await context.Send(getRtspBuffer(package));
                    }
                    catch
                    {
                        await removeSocket(context);
                    }
                }
            }
            else if (context != null)
            {
                try
                {
                    await context.Send(buffer);
                }
                catch
                {
                    await removeSocket(context);
                }
            }//WebSocketMessageType.Data      
        }

        private async Task removeSocket(WSRtspContext wsrtsp)
        {
            if (!String.IsNullOrEmpty(wsrtsp.ControlWebSocketId))
                await this.WebSocketConnectionManager.RemoveSocket(wsrtsp.ControlWebSocketId);
            if (!String.IsNullOrEmpty(wsrtsp.DataWebSocketId))
                await this.WebSocketConnectionManager.RemoveSocket(wsrtsp.DataWebSocketId);
        }

        //获取 WSP/1.1 WRAP 中的 WRAP.
        private static string getWSPCommand(string source)
        {
            string proto = "WSP/1.1";
            int protostart = source.IndexOf(proto);
            int protoend = source.IndexOf("\r\n", protostart);
            return source.Substring(proto.Length, protoend - proto.Length).Trim();
        }

        private static string getByKey(string source, string key)
        {
            int keyIndex = source.IndexOf(key);
            if (keyIndex > -1)
            {
                int indexKeyEnd = source.IndexOf("\r\n", keyIndex);
                if (indexKeyEnd > keyIndex)
                {
                    return source.Substring(keyIndex + key.Length + 1, indexKeyEnd - keyIndex - key.Length - 1).Trim();
                }
            }
            return null;
        }

        private static byte[] getRtspBuffer(string source)
        {
            if (source == null)
                return null;
            int wsmsgend = source.IndexOf("\r\n\r\n");
            if (wsmsgend > -1)
            {
                int rtsplen = source.Length - wsmsgend - 4;
                if (rtsplen > 0)
                {
                    string rtspmsg = source.Substring(wsmsgend + 4, rtsplen);
                    return ASCIIEncoding.UTF8.GetBytes(rtspmsg);
                }
            }
            return null;
        }
    }
}
